﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="SuperTrend.cs" company="">
//   
// </copyright>
// <summary>
//   The atr.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Linq;
using Systemathics.FrameWork;

namespace Systemathics.Indicators
{
    [Serializable]
    public sealed class SuperTrend : Indicator
    {
        private readonly Queue<Decimal> queue;
        private Bar bar_t;
        private Bar bar_t_1;
        private Decimal atr;
        private decimal a, b;
        private Trend TrenStyle;
        private enum Trend
        {
            Up,
            NoOne,
            Down,
        }

        public int ATRlength { get; private set; }
        public decimal Factor { get; private set; }
        public decimal UpBand { get; private set; }
        public decimal DownBand { get; private set; }

        public SuperTrend(Instrument instr, BarType bt, int barValue, int atRlength, decimal factor)
            : base(instr, Data.Bar, bt, barValue)
        {
            queue = new Queue<Decimal>();
            ATRlength = atRlength;
            a = new decimal((ATRlength - 1) / (double)ATRlength);
            b = new decimal(1 / (double)ATRlength);
            Factor = factor;
            ATRlength = atRlength;
            UpBand = 0;
            DownBand = 0;
            TrenStyle = Trend.NoOne;
        }

        protected override void Calculate(object price)
        {
            if (price is Bar)
            {
                bar_t = price as Bar;
                if (bar_t.High != Decimal.Zero && bar_t.Low != Decimal.Zero)
                {
                    if (bar_t_1 != null)
                    {
                        var trueRange =
                            Math.Max(Math.Max(Math.Abs(bar_t.High - bar_t.Low), Math.Abs(bar_t.High - bar_t_1.Close)),
                                     Math.Abs(bar_t.Low - bar_t_1.Close));
                        if (queue.Count < ATRlength)
                        {
                            queue.Enqueue(trueRange);
                            atr = queue.Average();
                        }
                        else
                        {
                            atr = a*atr + b*trueRange;
                            UpBand = bar_t.Median + Factor*atr;
                            DownBand = bar_t.Median - Factor*atr;

                            if (bar_t.Close > UpBand)
                            {
                                Add(bar_t.BeginTime, DownBand);
                                TrenStyle = Trend.Up;
                                IndicatorCalculated(this);
                            }
                            else if (bar_t.Close < DownBand)
                            {
                                Add(bar_t.BeginTime, UpBand);
                                TrenStyle = Trend.Down;
                                IndicatorCalculated(this);
                            }
                            else if(bar_t.Close <= UpBand && bar_t.Close >= DownBand)
                            {
                                if(TrenStyle == Trend.Up)
                                {
                                    Add(bar_t.BeginTime, DownBand);
                                    IndicatorCalculated(this);
                                }
                                else if (TrenStyle == Trend.Down)
                                {
                                    Add(bar_t.BeginTime, UpBand);
                                    IndicatorCalculated(this);
                                }
                            }
                        }
                    }
                    bar_t_1 = bar_t;
                }
                else
                    new RemotingLogClient().Trace(
                        new FireMessageEventArgs(
                            "SuperTrend: Cannot calculate an ATR on Data either than Bar, check ATR consructor",
                            DateTime.Now.TimeOfDay));
            }
        }
    }
}